import * as fs from "node:fs";
import path from "node:path";

interface TraverseTree<T> {
    value: T
    children?: TraverseTree<T>[]
    isLeaf: boolean
}

export class FileNode implements TraverseTree<string> {
    get children(): TraverseTree<string>[] | undefined {
        if (!this.isLeaf) {
            return fs.readdirSync(this.value).map(e => new FileNode(path.resolve(this.value, e)))
        } else {
            return undefined
        }
    }
    get isLeaf(): boolean {
        const info = fs.statSync(this.value)
        return !info.isDirectory()
    }
    value: string
    constructor(value: string) {
        this.value = value
    }
}

export class Traverser<T> {
    root: TraverseTree<T>
    action: (node?: T) => void = () => {}
    filter: (node: T) => boolean = () => true
    constructor(root: TraverseTree<T>) {
        this.root = root
    }
    traverse() {
        let stack:  TraverseTree<T>[] = []
        stack.push(this.root)
        while (stack.length > 0) {
            let current = stack.pop()!
            if (current.isLeaf) {
                if (this.filter(current.value)) {
                    this.action(current.value)
                }
            } else {
                if (current.children && current.children.length > 0) {
                    stack.push(...current.children)
                }
            }
        }
    }

}